// Copyright (c) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::{parse_document, structure::*, IoReader, StrReader};
use std::{
    cell::RefCell,
    cmp::Ordering,
    fs::File,
    io::{BufReader, Read},
    rc::{Rc, Weak},
};

/// `DocumentMethod`, which provides some methods similar to `Interface
/// Document`.
///
/// # Association
/// [Interface Document](https://www.w3.org/TR/DOM-Level-3-Core/core.html#i-Document)
pub trait DocumentMethod: NodeMethod {
    /// An access to the child node that is the document element of the
    /// document.
    ///
    /// # Association
    /// [Document::documentElement](https://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-87CD092)
    ///
    /// # Example
    /// ```
    /// use ylong_xml::{Document, DocumentMethod};
    ///
    /// let document = Document::new();
    /// assert!(document.document_element().is_none());
    /// ```
    fn document_element(&self) -> Option<Element>;

    /// An attribute specifying, as part of the XML declaration, the encoding
    /// of this document. This is `None` when unspecified.
    ///
    /// # Association
    /// [Document::xmlEncoding](https://www.w3.org/TR/DOM-Level-3-Core/core.html#Document3-encoding)
    ///
    /// # Example
    /// ```
    /// use ylong_xml::{Document, DocumentMethod};
    ///
    /// let document = Document::new();
    /// assert!(document.xml_encoding().is_none());
    /// ```
    fn xml_encoding(&self) -> Option<Encoding>;

    /// Set the encoding of this document, or reset it to `None`.
    ///
    /// # Example
    /// ```
    /// use ylong_xml::{Document, DocumentMethod, Encoding};
    ///
    /// let mut document = Document::new();
    /// assert_eq!(document.xml_encoding(), None);
    /// document.set_xml_encoding(Some(Encoding::Utf8));
    /// assert_eq!(document.xml_encoding(), Some(Encoding::Utf8));
    /// ```
    fn set_xml_encoding(&mut self, encoding: Option<Encoding>);

    /// An attribute specifying, as part of the XML declaration, the version
    /// number of this document. If there is no declaration, the value is "1.0".
    ///
    /// # Association
    /// [Document::xmlVersion](https://www.w3.org/TR/DOM-Level-3-Core/core.html#Document3-version)
    ///
    /// # Example
    /// ```
    /// use ylong_xml::{Document, DocumentMethod};
    ///
    /// let document = Document::new();
    /// assert_eq!(document.version(), "1.0");
    /// ```
    fn version(&self) -> String;

    /// Set the xml version of the document.
    ///
    /// # Errors
    /// * INVALID_CHARACTER_ERR:
    /// Raised if the input `version` string has invalid characters.
    ///
    /// # Association
    /// [Document::xmlVersion](https://www.w3.org/TR/DOM-Level-3-Core/core.html#Document3-version)
    ///
    /// # Example
    /// ```
    /// use ylong_xml::{Document, DocumentMethod};
    ///
    /// let mut document = Document::new();
    /// assert_eq!(document.version(), "1.0");
    /// assert!(document.set_version("1.1").is_ok());
    /// assert_eq!(document.version(), "1.1");
    /// ```
    fn set_version(&mut self, version: &str) -> Result<(), XmlError>;

    /// An attribute specifying, as part of the XML declaration, whether this
    /// document is standalone. This is `None` when unspecified.
    ///
    /// # Differences
    /// You will get `None` if standalone is unspecified instead of `false`.
    ///
    /// # Association
    /// [Document::xmlStandalone](https://www.w3.org/TR/DOM-Level-3-Core/core.html#Document3-standalone)
    ///
    /// # Example
    /// ```
    /// use ylong_xml::{Document, DocumentMethod};
    ///
    /// let document = Document::new();
    /// assert!(document.standalone().is_none());
    /// ```
    fn standalone(&self) -> Option<bool>;

    /// Set the standalone of the document, or reset it to `None`.
    ///
    /// # Association
    /// [Document::xmlStandalone](https://www.w3.org/TR/DOM-Level-3-Core/core.html#Document3-standalone)
    ///
    /// # Example
    /// ```
    /// use ylong_xml::{Document, DocumentMethod};
    ///
    /// let mut document = Document::new();
    /// assert!(document.standalone().is_none());
    /// document.set_standalone(Some(true));
    /// assert_eq!(document.standalone(), Some(true));
    /// ```
    fn set_standalone(&mut self, standalone: Option<bool>);

    /// Create an `Element` of the given `Name`.
    ///
    /// # Association
    /// [Document::createElementNS](https://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-DocCrElNS)
    ///
    /// # Example
    /// ```
    /// use ylong_xml::{Document, DocumentMethod};
    ///
    /// let document = Document::new();
    /// let element = document.create_element("Element").unwrap();
    /// ```
    fn create_element(&self, name: &str) -> Result<Element, XmlError>;

    /// Create a `Text` of the given `value` string.
    ///
    /// # Association
    /// [Document::createTextNode](https://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1975348127)
    ///
    /// # Example
    /// ```
    /// use ylong_xml::{Document, DocumentMethod};
    ///
    /// let document = Document::new();
    /// let value = "Text";
    /// let text = document.create_text(value);
    /// ```
    fn create_text(&self, value: &str) -> Result<Text, XmlError>;

    /// Create a `Comment` of the given `value` string.
    ///
    /// # Association
    /// [Document::createComment](https://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1334481328)
    ///
    /// # Example
    /// ```
    /// use ylong_xml::{Document, DocumentMethod};
    ///
    /// let document = Document::new();
    /// let value = "Comment";
    /// let comment = document.create_comment(value);
    /// ```
    fn create_comment(&self, value: &str) -> Result<Comment, XmlError>;

    /// Create a `CdataSection` of the given `value` string.
    ///
    /// # Association
    /// [Document::createCDATASection](https://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-D26C0AF8)
    ///
    /// # Example
    /// ```
    /// use ylong_xml::{Document, DocumentMethod};
    ///
    /// let document = Document::new();
    /// let value = "CDATASection";
    /// let cdata_section = document.create_comment(value);
    /// ```
    fn create_cdata_section(&self, value: &str) -> Result<CdataSection, XmlError>;

    /// Create a `Attribute` of the given `Name` and `value` string.
    ///
    /// # Differences
    /// A `value` parameter needs to be passed in.
    ///
    /// # Association
    /// [Document::createAttributeNS](https://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-DocCrAttrNS)
    ///
    /// # Example
    /// ```
    /// use ylong_xml::{Document, DocumentMethod};
    ///
    /// let document = Document::new();
    /// let name = "Attribute";
    /// let value = "Attribute";
    /// let attribute = document.create_attribute(name, value);
    /// ```
    fn create_attribute(&self, name: &str, value: &str) -> Result<Attribute, XmlError>;
}

/// The `Document` structure, the instance of `Interface Document`.
///
/// # Association
/// [Interface Document](https://www.w3.org/TR/DOM-Level-3-Core/core.html#i-Document)
///
/// # Example
/// ```
/// use ylong_xml::{Document, DocumentMethod, Comment, Element, ParentNodeMethod};
///
/// // Create an XML document.
/// let mut document = Document::new();
///
/// // You can create child node of this document by using a series of `Document`'s
/// // `create` methods.
/// // For example: Create an element which belongs to this document.
/// let element = document.create_element("Element").unwrap();
/// // You can also create child node of this document using `new` method.
/// // For example: Create a element which belongs to this document.
/// let element = Element::new("Element", &document).unwrap();
///
/// // After modifying the child node, you can insert it into the document by
/// // using a series of `Document`'s insertion methods.
/// // For example: Using `Document::append_child` to append child node to the document.
/// assert!(document.append_child(element).is_ok());
/// ```
#[derive(Debug, Clone)]
pub struct Document {
    // The `inner` member contains all the `Document`'s information.
    // We use a structure to wrap the member to distinguish the type of
    // the current member -- a `Node` or a `Document`, for example.
    pub(crate) inner: Rc<RefCell<DocumentInner>>,
}

impl Document {
    /// Create a default `Document`. Some parts of it are set, other parts are
    /// not.
    ///
    /// * `version` is set to `1.0`.
    /// * `xml_encoding` is not set.
    /// * `standalone` is not set.
    /// * No children are added to it.
    ///
    /// # Example
    /// ```
    /// use ylong_xml::{Document, DocumentMethod, ParentNodeMethod};
    ///
    /// let document = Document::new();
    /// assert_eq!(document.version(), "1.0");
    /// assert!(document.xml_encoding().is_none());
    /// assert!(document.standalone().is_none());
    /// assert_eq!(document.has_children(), false);
    /// ```
    pub fn new() -> Self {
        Self {
            inner: Rc::new(RefCell::new(DocumentInner::default())),
        }
    }

    /// Try to parse a text string and then generate a `Document`
    ///
    /// # Example
    /// ```
    /// use ylong_xml::Document;
    ///
    /// let text = "<br/>";
    /// let document = Document::from_text(text).unwrap();
    /// ```
    pub fn from_text(text: &str) -> Result<Self, XmlError> {
        let mut reader = StrReader::new(text);
        parse_document(&mut reader)
    }

    /// Try to parse a file with the given path, and then generate a `Document`.
    ///
    /// # Example
    /// ```not run
    /// use ylong_xml::Document;
    ///
    /// let path = "./test.txt";
    /// let document = Document::from_file(path).unwrap();
    /// ```
    pub fn from_file(path: &str) -> Result<Self, XmlError> {
        let file = File::open(path)?;
        Self::from_reader(file)
    }

    /// Try to parse an object which implements `std::io::Read`, and then
    /// generate a `Document`.
    ///
    /// # Example
    /// ```not run
    /// use std::fs::File;
    /// use ylong_xml::Document;
    ///
    /// let file = File::open("./test.txt").unwrap();
    /// let document = Document::from_reader(file).unwrap();
    /// ```
    pub fn from_reader<R: Read>(io: R) -> Result<Self, XmlError> {
        let mut reader = IoReader::new(BufReader::new(io));
        parse_document(&mut reader)
    }

    // /// Serialize the `Document` as a compact format string.
    // pub fn to_string(&self) -> Result<String, XmlError> {
    //     let mut vec = Vec::new();
    //     CompactOutput::output(self, &mut vec)?;
    //     Ok(unsafe { String::from_utf8_unchecked(vec) })
    // }
    //
    // /// Serialize the `Document` and then output it to a writer.
    // pub fn to_writer<W: Write>(&self, writer: &mut W) -> Result<(), XmlError> {
    //     let mut writer = BufWriter::new(writer);
    //     CompactOutput::output(self, &mut writer)
    // }
}

impl NodeMethod for Document {
    fn as_node(&self) -> Node {
        Node::Document(self.clone())
    }

    fn name(&self) -> String {
        String::from("#document")
    }

    fn node_type(&self) -> NodeType {
        NodeType::Document
    }

    fn owner_document(&self) -> Option<Document> {
        None
    }
}

impl ParentNodeInternalMethod for Document {
    type WeakNode = WeakDocument;

    fn downgrade(&self) -> Self::WeakNode {
        WeakDocument {
            inner: Rc::downgrade(&self.inner),
        }
    }

    fn try_as_child_node(&self) -> Option<ChildNode> {
        None
    }

    fn is_child_allowed(&self, node: &ChildNode) -> bool {
        matches!(node, ChildNode::Element(_) | ChildNode::Comment(_))
    }

    fn is_same_document(&self, node: &ChildNode) -> bool {
        if let Some(ref document) = node.owner_document() {
            return document == self;
        }
        false
    }
}

impl ParentNodeMethod for Document {
    fn as_parent_node(&self) -> ParentNode {
        ParentNode::Document(self.clone())
    }

    fn children(&self) -> NodeList<ChildNode> {
        self.inner.borrow().children.clone()
    }

    fn insert_before<A, B>(&mut self, new_child: A, ref_child: &B) -> Result<(), XmlError>
    where
        A: ChildNodeMethod,
        B: ChildNodeMethod,
    {
        let new_child = new_child.as_child_node();
        let ref_child = ref_child.as_child_node();

        // Check if `new_child` is an ancestor node.
        // Check if `new_child` is an allowed child node.
        if self.is_descendant_of(&new_child) || !self.is_child_allowed(&new_child) {
            return Err(DomException::HierarchyRequestErr.into());
        }
        // Check if `new_child` is from the same `Document` as `self`.
        if !self.is_same_document(&new_child) {
            return Err(DomException::WrongDocumentErr.into());
        }
        let children = self.children();
        let mut list_mut = children.list.borrow_mut();

        // Returns `NotFoundErr` if `ref_child` is not found.
        let mut insert_pos = list_mut
            .iter()
            .position(|n| n == &ref_child)
            .ok_or(DomException::NotFoundErr)?;

        // The same child node needs to be deleted before insertion.
        if let Some(removed_pos) = list_mut.iter().position(|n| n == &new_child) {
            // If we find it, then delete it.
            list_mut.remove(removed_pos);
            // Since the content of the list changes, the insertion position
            // needs to be changed.
            if insert_pos > removed_pos {
                insert_pos -= 1;
            }
            list_mut.insert(insert_pos, new_child);
        } else {
            // `Document` can only have one `Element`.
            if let Ok(element) = new_child.as_element() {
                if self.document_element().is_some() {
                    return Err(DomException::HierarchyRequestErr.into());
                } else {
                    self.inner.borrow_mut().document_element = Some(element.clone());
                }
            }
            list_mut.insert(insert_pos, new_child);
            // Set parent of the inserted node as the current node.
            list_mut[insert_pos].set_parent(Some(self.as_parent_node().downgrade()));
        }
        Ok(())
    }

    fn replace_child<A, B>(&mut self, new_child: A, old_child: &B) -> Result<(), XmlError>
    where
        A: ChildNodeMethod,
        B: ChildNodeMethod,
    {
        let new_child = new_child.as_child_node();
        let old_child = old_child.as_child_node();

        // Check if `new_child` is an ancestor node.
        // Check if `new_child` is an allowed child node.
        if self.is_descendant_of(&new_child) || !self.is_child_allowed(&new_child) {
            return Err(DomException::HierarchyRequestErr.into());
        }
        // Check if `new_child` is from the same `Document` as `self`.
        if !self.is_same_document(&new_child) {
            return Err(DomException::WrongDocumentErr.into());
        }

        let children = self.children();
        let mut list_mut = children.list.borrow_mut();

        // Returns `NotFoundErr` if `old_child` is not found.
        let replace_pos = list_mut
            .iter()
            .position(|n| n == &old_child)
            .ok_or(DomException::NotFoundErr)?;

        // Set parent of the replaced node to be `None`.
        list_mut[replace_pos].set_parent(None);

        // The same child node needs to be deleted before insertion.
        if let Some(remove_pos) = list_mut.iter().position(|n| n == &new_child) {
            list_mut.remove(remove_pos);

            match replace_pos.cmp(&remove_pos) {
                Ordering::Greater => list_mut[replace_pos - 1] = new_child.clone(),
                Ordering::Equal => list_mut.insert(replace_pos, new_child.clone()),
                Ordering::Less => list_mut[replace_pos] = new_child.clone(),
            }
        } else {
            if new_child.is_element()
                && list_mut.iter().any(|n| n.is_element())
                && !list_mut[replace_pos].is_element()
            {
                return Err(DomException::HierarchyRequestErr.into());
            }
            list_mut[replace_pos] = new_child.clone();
            // Set parent of the inserted node to be the current node.
            list_mut[replace_pos].set_parent(Some(self.as_parent_node().downgrade()));
        }

        match (new_child.is_element(), old_child.is_element()) {
            (false, false) => {}
            (false, true) => self.inner.borrow_mut().document_element = None,
            _ => self.inner.borrow_mut().document_element = new_child.into_element().ok(),
        }
        Ok(())
    }

    fn remove_child<A>(&mut self, old_child: &A) -> Result<(), XmlError>
    where
        A: ChildNodeMethod,
    {
        let old_child = old_child.as_child_node();

        let children = self.children();
        let mut list_mut = children.list.borrow_mut();

        // Returns `NotFoundErr` if `old_child` is not found.
        let remove_pos = list_mut
            .iter()
            .position(|n| n == &old_child)
            .ok_or(DomException::NotFoundErr)?;

        if old_child.is_element() {
            self.inner.borrow_mut().document_element = None;
        }
        list_mut[remove_pos].set_parent(None);
        list_mut.remove(remove_pos);
        Ok(())
    }

    fn append_child<A>(&mut self, new_child: A) -> Result<(), XmlError>
    where
        A: ChildNodeMethod,
    {
        let new_child = new_child.as_child_node();

        // Check if `new_child` is an ancestor node.
        // Check if `new_child` is an allowed child node.
        if self.is_descendant_of(&new_child) || !self.is_child_allowed(&new_child) {
            return Err(DomException::HierarchyRequestErr.into());
        }
        // Check if `new_child` is from the same `Document` as `self`.
        if !self.is_same_document(&new_child) {
            return Err(DomException::WrongDocumentErr.into());
        }

        let children = self.children();
        let mut list_mut = children.list.borrow_mut();

        if let Some(remove_pos) = list_mut.iter().position(|n| n == &new_child) {
            list_mut.remove(remove_pos);
            list_mut.push(new_child);
        } else {
            if new_child.is_element() && list_mut.iter().any(|n| n.is_element()) {
                return Err(DomException::HierarchyRequestErr.into());
            }
            list_mut.push(new_child.clone());
            // Set parent of the inserted node to be the current node.
            let len = list_mut.len();
            list_mut[len - 1].set_parent(Some(self.as_parent_node().downgrade()));
            self.inner.borrow_mut().document_element = new_child.into_element().ok();
        }
        Ok(())
    }
}

impl DocumentMethod for Document {
    fn document_element(&self) -> Option<Element> {
        self.inner.borrow().document_element.clone()
    }

    fn xml_encoding(&self) -> Option<Encoding> {
        self.inner.borrow().decl.xml_encoding()
    }

    fn set_xml_encoding(&mut self, encoding: Option<Encoding>) {
        self.inner.borrow_mut().decl.set_xml_encoding(encoding);
    }

    fn version(&self) -> String {
        self.inner.borrow().decl.version()
    }

    fn set_version(&mut self, version: &str) -> Result<(), XmlError> {
        self.inner.borrow_mut().decl.set_version(version)
    }

    fn standalone(&self) -> Option<bool> {
        self.inner.borrow().decl.standalone()
    }

    fn set_standalone(&mut self, standalone: Option<bool>) {
        self.inner.borrow_mut().decl.set_standalone(standalone)
    }

    fn create_element(&self, name: &str) -> Result<Element, XmlError> {
        Element::new(name, self)
    }

    fn create_text(&self, value: &str) -> Result<Text, XmlError> {
        Text::new(value, self)
    }

    fn create_comment(&self, value: &str) -> Result<Comment, XmlError> {
        Comment::new(value, self)
    }

    fn create_cdata_section(&self, value: &str) -> Result<CdataSection, XmlError> {
        CdataSection::new(value, self)
    }

    fn create_attribute(&self, name: &str, value: &str) -> Result<Attribute, XmlError> {
        Attribute::new(name, value, self)
    }
}

impl Default for Document {
    fn default() -> Self {
        Self::new()
    }
}

impl PartialEq for Document {
    fn eq(&self, other: &Self) -> bool {
        self.inner.as_ptr() == other.inner.as_ptr()
    }
}

#[derive(Debug, Clone)]
pub struct WeakDocument {
    inner: Weak<RefCell<DocumentInner>>,
}

impl WeakParentNodeMethod for WeakDocument {
    type Node = Document;

    fn upgrade(&self) -> Option<Self::Node> {
        self.inner.upgrade().map(|inner| Document { inner })
    }

    fn as_weak_parent_node(&self) -> WeakParentNode {
        WeakParentNode::Document(self.clone())
    }
}

impl PartialEq for WeakDocument {
    fn eq(&self, other: &Self) -> bool {
        self.inner.as_ptr() == other.inner.as_ptr()
    }
}

#[derive(Debug, Default)]
pub(crate) struct DocumentInner {
    // Definition: XML documents should begin with an XML declaration which
    // specifies the version of XML being used.
    pub(crate) decl: XmlDecl,
    pub(crate) children: NodeList<ChildNode>,
    pub(crate) document_element: Option<Element>,
}

#[cfg(test)]
mod ut_structure_document {
    use crate::{structure::*, Document};
    use std::fs::File;

    /*
     * @title  UT test for document read file from io
     * @design Condition Coverage
     * @precon NA
     * @brief  1. Creat path.
     *         2. Call from_reader to read path。
     *         4. Check if result is correct
     * @expect 1. false。
     * @auto   yes
     */
    #[test]
    fn ut_document_io_read_file() {
        let file = File::open("./src/structure/error.rs").unwrap();
        let document = Document::from_reader(file);
        assert!(document.is_err());
    }

    /*
     * @title  UT test for document read file from path
     * @design Condition Coverage
     * @precon NA
     * @brief  1. Creat path.
     *         2. Call from_file to read path。
     *         4. Check if result is correct
     * @expect 1. false。
     * @auto   yes
     */
    #[test]
    fn ut_document_read_file() {
        let path = "./src/structure/error.rs";
        let document = Document::from_file(path);
        assert!(document.is_err());
    }

    /*
     * @title  UT test for document append child
     * @design Condition Coverage
     * @precon NA
     * @brief  1. Call `default()` method to create a document.
     *         2. Call create_text get child。
     *         3. Call append_child to add child
     *         4. Check if child is correct
     * @expect 1. false。
     * @auto   yes
     */
    #[test]
    fn ut_document_append_child_err() {
        // Create a `Document`.
        let mut document = Document::default();
        let child = document.create_text("Text").unwrap();
        let res = document.append_child(child);
        assert!(res.is_err());
    }

    /// UT test case for `Document::new()`.
    ///
    /// # Brief
    /// 1. Call `new()` method to create a `Document`.
    /// 2. Check if parts of the `Document` are default values.
    #[test]
    fn ut_document_new() {
        let document = Document::new();
        let document_inner = document.inner.borrow();
        assert_eq!(document_inner.decl.version, "1.0");
        assert_eq!(document_inner.decl.xml_encoding, None);
        assert_eq!(document_inner.decl.standalone, None);
        assert_eq!(document_inner.children.len(), 0);
        assert_eq!(document_inner.document_element, None);
    }

    /// UT test case for `Document::as_node()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Call `as_node()` method to convert `document` to `Node`.
    /// 3. Check if `Node::Document(document)` is obtained.
    #[test]
    fn ut_document_as_node() {
        let document = Document::new();
        let node = document.as_node();
        assert_eq!(node, Node::Document(document));
    }

    /// UT test case for `Document::name()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Call `name()` method to obtain `document`'s name.
    /// 3. Check if the obtained name is `#document`.
    #[test]
    fn ut_document_name() {
        let document = Document::new();
        assert_eq!(document.name(), "#document");
    }

    /// UT test case for `Document::node_type()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Call `node_type()` method to obtain `document`'s type.
    /// 3. Check if this obtained node type is `NodeType::Document`.
    #[test]
    fn ut_document_node_type() {
        let document = Document::new();
        assert_eq!(document.node_type(), NodeType::Document);
    }

    /// UT test case for `Document::owner_document()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Call `owner_document()` method to obtain `document`'s owner document.
    /// 3. Check if `Document`'s owner document is `None`.
    #[test]
    fn ut_document_owner_document() {
        let document = Document::new();
        assert_eq!(document.owner_document(), None);
    }

    /// UT test case for `Document::downgrade()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Call `downgrade()` method to obtained the `document`'s weak reference.
    /// 3. Check if the weak reference is valid.
    #[test]
    fn ut_document_downgrade() {
        let document = Document::new();
        let weak_document = document.downgrade();
        assert_eq!(weak_document.upgrade(), Some(document));
    }

    /// UT test case for `Document::try_as_child_node()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Call `try_as_child_node()` method to obtained the `ChildNode` form
    /// of `document`.
    /// 3. Check if the result is `None`.
    #[test]
    fn ut_document_try_as_child_node() {
        let document = Document::new();
        assert_eq!(document.try_as_child_node(), None);
    }

    /// UT test case for `Document::is_child_allowed()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Create a `Text` called `text` and create a `Comment` called `comment`.
    /// 3. Call `is_child_allowed()` method to check if `text` or `comment` is allowed.
    #[test]
    fn ut_document_is_child_allowed() {
        let document = Document::new();
        let text = document.create_text("Text").unwrap();
        let comment = document.create_comment("Comment").unwrap();
        assert!(!document.is_child_allowed(&text.as_child_node()));
        assert!(document.is_child_allowed(&comment.as_child_node()));
    }

    /// UT test case for `Document::is_same_document()`.
    ///
    /// # Brief
    /// 1. Create two `Document`s called `document1` and `document2`.
    /// 2. Create a `Comment` of `document1` called `comment1`, and create a
    /// `Comment` of `document2` called `comment2`.
    /// 3. Call `is_same_document()` method to check the relationship of these
    /// objects.
    #[test]
    fn ut_document_is_same_document() {
        let document1 = Document::new();
        let document2 = Document::new();
        let comment1 = document1.create_comment("Comment").unwrap();
        let comment2 = document2.create_comment("Comment").unwrap();

        assert!(document1.is_same_document(&comment1.as_child_node()));
        assert!(!document1.is_same_document(&comment2.as_child_node()));
        assert!(!document2.is_same_document(&comment1.as_child_node()));
        assert!(document2.is_same_document(&comment2.as_child_node()));
    }

    /// UT test case for `Document::as_parent_node()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Call `as_parent_node()` method to convert `document` to a `ParentNode`.
    /// 3. Check if `ParentNode::Document(document)` is obtained.
    #[test]
    fn ut_document_as_parent_node() {
        let document = Document::new();
        let node = document.as_parent_node();
        assert_eq!(node, ParentNode::Document(document));
    }

    /// UT test case for `Document::children()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Add any number of child nodes to the `document`.
    /// 3. Call `children()` method to obtained the `document`'s children list.
    /// 4. Check if the length of the children list is correct.
    #[test]
    fn ut_document_children() {
        let mut document = Document::new();
        let children = document.children();
        assert_eq!(document.children().len(), 0);

        let child = document.create_comment("Comment").unwrap();
        let child_clone = child.clone();
        let _ = document.append_child(child);
        assert_eq!(children.len(), 1);
        assert_eq!(children.item(0).unwrap(), child_clone.as_child_node());
    }

    /// UT test case for `Document::has_children()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Add any number of child nodes to the `document`.
    /// 3. Call `has_children()` method to check if the `document` has children.
    #[test]
    fn ut_document_has_children() {
        let mut document = Document::new();
        assert!(!document.has_children());

        let child = document.create_comment("Comment").unwrap();
        let _ = document.append_child(child);
        assert!(document.has_children());
    }

    /// UT test case for `Document::first_children()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Add any number of child nodes to the `document`.
    /// 3. Call `first_child()` method to check if the `document` has children.
    /// 4. Check if the first child is correct.
    #[test]
    fn ut_document_first_children() {
        let mut document = Document::new();
        assert_eq!(document.first_child(), None);

        let child = document.create_comment("Comment").unwrap();
        let child_clone = child.clone();
        let _ = document.append_child(child);
        assert_eq!(document.first_child().unwrap(), child_clone.as_child_node());
    }

    /// UT test case for `Document::last_children()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Add any number of child nodes to the `document`.
    /// 3. Call `last_child()` method to check if the `document` has children.
    /// 4. Check if the last child is correct.
    #[test]
    fn ut_document_last_children() {
        let mut document = Document::new();
        assert_eq!(document.last_child(), None);

        let child = document.create_comment("Comment").unwrap();
        let child_clone = child.clone();
        let _ = document.append_child(child);
        assert_eq!(document.last_child().unwrap(), child_clone.as_child_node());
    }

    /// UT test case for `Document::insert_before()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Add any number of child nodes to the `document`.
    /// 3. Call `insert_before()` method to add an additional child node to `document`.
    /// 4. Check if the children list of `document` is correct.
    #[test]
    fn ut_document_insert_before() {
        // Create a document to be tested.
        let mut document = Document::new();
        // Add a child to it, because we need a `ref_child` to specify the position.
        let child_init_first = document.create_comment("Comment").unwrap();
        let _ = document.append_child(child_init_first);
        assert!(document.has_children());

        // Get a reference to the document's children.
        let children = document.children();

        // Branch 1: The given `new_child` is not from the same document.
        let other_document = Document::new();
        let other_child = other_document.create_comment("Comment").unwrap();
        let ref_child = children.item(0).unwrap();
        assert_eq!(
            document.insert_before(other_child, &ref_child).err(),
            Some(DomException::WrongDocumentErr.into()),
        );

        // Branch 2: The given `new_child` is not an allowed child node.
        let child_not_allowed = document.create_text("Text").unwrap();
        let ref_child = children.item(0).unwrap();
        assert_eq!(
            document.insert_before(child_not_allowed, &ref_child).err(),
            Some(DomException::HierarchyRequestErr.into()),
        );

        // Branch 3: Cannot find the given `ref_child`.
        let child_allowed = document.create_comment("Comment").unwrap();
        let child_not_belongs_to_it = document.create_comment("Comment").unwrap();
        assert_eq!(
            document
                .insert_before(child_allowed, &child_not_belongs_to_it)
                .err(),
            Some(DomException::NotFoundErr.into()),
        );

        // Before the following tests, we append a new child to the children list.
        let child_init_second = document.create_comment("Comment").unwrap();
        let _ = document.append_child(child_init_second);
        assert_eq!(children.len(), 2);
        // After this operation, the list is as follows:
        //
        // list:                        document_element:
        // +----------+----------+      +----------+
        // |   first  |  second  |      |  (None)  |
        // +----------+----------+      +----------+
        //
        // The `first` represents the first node which was inserted at the time
        // we created the document, And the `second` represents the second node inserted
        // before.
        //
        // There is no element in the children list now, so the document have no
        // `document_element`.
        //
        // Branch 4: There is no node the same as the given `new_child`,
        // and the node is not an `Element`.
        let child_opr = document.create_comment("Comment").unwrap();
        let child_opr_clone = child_opr.clone();
        let ref_child = children.item(1).unwrap();
        assert!(document.insert_before(child_opr, &ref_child).is_ok());
        // After this operation, the list is as follows:
        //
        // list:                                   document_element:
        // +----------+----------+----------+      +----------+
        // |   first  |   opr    |  second  |      |  (None)  |
        // +----------+----------+----------+      +----------+
        //
        // The `opr` represents the node which was inserted by the `Branch 4` operation.
        assert_eq!(children.len(), 3);
        assert_eq!(children.item(1).unwrap(), child_opr_clone.as_child_node());
        assert_eq!(document.document_element(), None);
        assert_eq!(child_opr_clone.parent(), Some(document.as_parent_node()));

        // Branch 5: There is a node the same as the given `new_child`, we insert
        // `new_child` at the position where contains that node. The node is not an
        // `Element`.
        let child_opr = children.item(1).unwrap();
        let child_opr_clone = child_opr.clone();
        let ref_child = children.item(1).unwrap();
        assert!(document.insert_before(child_opr, &ref_child).is_ok());
        // After this operation, the list is as follows:
        //
        // list:                                   document_element:
        // +----------+----------+----------+      +----------+
        // |   first  |   opr    |  second  |      |  (None)  |
        // +----------+----------+----------+      +----------+
        //
        // The `opr` represents the node which was inserted by the `Branch 5` operation.
        // The origin node has been replaced.
        assert_eq!(children.len(), 3);
        assert_eq!(children.item(1).unwrap(), child_opr_clone.as_child_node());
        assert_eq!(document.document_element(), None);
        assert_eq!(child_opr_clone.parent(), Some(document.as_parent_node()));

        // Branch 6: There is a node the same as the given `new_child`, we insert
        // `new_child` at the position which in front of that node. The node is not an
        // `Element`.
        let child_opr = children.item(1).unwrap();
        let child_opr_clone = child_opr.clone();
        let ref_child = children.item(0).unwrap();
        assert!(document.insert_before(child_opr, &ref_child).is_ok());
        // After this operation, the list is as follows:
        //
        // list:                                   document_element:
        // +----------+----------+----------+      +----------+
        // |   opr    |   first  |  second  |      |  (None)  |
        // +----------+----------+----------+      +----------+
        //
        // The `opr` represents the node which was inserted by the `Branch 6` operation.
        // The origin node has been removed.
        assert_eq!(children.len(), 3);
        assert_eq!(children.item(0).unwrap(), child_opr_clone.as_child_node());
        assert_eq!(document.document_element(), None);
        assert_eq!(child_opr_clone.parent(), Some(document.as_parent_node()));

        // Branch 7: There is a node the same as the given `new_child`, we insert
        // `new_child` at the position which behind that node. The node is not an
        // `Element`.
        let child_opr = children.item(0).unwrap();
        let child_opr_clone = child_opr.clone();
        let ref_child = children.item(2).unwrap();
        assert!(document.insert_before(child_opr, &ref_child).is_ok());
        // After this operation, the list is as follows:
        // list:                                   document_element:
        // +----------+----------+----------+      +----------+
        // |   first  |   opr    |  second  |      |  (None)  |
        // +----------+----------+----------+      +----------+
        //
        // The `opr` represents the node which was inserted by the `Branch 7` operation.
        // The origin node has been removed.
        assert_eq!(children.len(), 3);
        assert_eq!(children.item(1).unwrap(), child_opr_clone.as_child_node());
        assert_eq!(document.document_element(), None);
        assert_eq!(child_opr_clone.parent(), Some(document.as_parent_node()));

        // Before the following tests, we remove the `opr` node in the children list.
        let child_opr = children.item(1).unwrap();
        let _ = document.remove_child(&child_opr);
        // After this operation, the list is as follows:
        //
        // list:                        document_element:
        // +----------+----------+      +----------+
        // |   first  |  second  |      |  (None)  |
        // +----------+----------+      +----------+
        assert_eq!(children.len(), 2);
        assert_eq!(document.document_element(), None);
        assert_eq!(child_opr.parent(), None);

        // Branch 8: There is no node the same as the given `new_child`,
        // and the node is an `Element`.
        let child_opr = document.create_element("Element").unwrap();
        let child_opr_clone = child_opr.clone();
        let ref_child = children.item(1).unwrap();
        assert!(document.insert_before(child_opr, &ref_child).is_ok());
        // After this operation, the list is as follows:
        //
        // list:                                   document_element:
        // +----------+----------+----------+      +----------+
        // |   first  |   opr    |  second  |      |    opr   |
        // +----------+----------+----------+      +----------+
        //
        // The `opr` represents the node which was inserted by the `Branch 8` operation.
        //
        // There is one element in the children list now, so the `document_element`
        // member has a value.
        assert_eq!(children.len(), 3);
        assert_eq!(children.item(1).unwrap(), child_opr_clone.as_child_node());
        assert_eq!(child_opr_clone.parent(), Some(document.as_parent_node()));
        assert_eq!(document.document_element(), Some(child_opr_clone));

        // Branch 9: There is a node the same as the given `new_child`, we insert
        // `new_child` at the position where contains that node. The node is not an
        // `Element`.
        let child_opr = children.item(1).unwrap();
        let child_opr_clone = child_opr.clone();
        let ref_child = children.item(1).unwrap();
        assert!(document.insert_before(child_opr, &ref_child).is_ok());
        // After this operation, the list is as follows:
        //
        // list:                                   document_element:
        // +----------+----------+----------+      +----------+
        // |   first  |   opr    |  second  |      |    opr   |
        // +----------+----------+----------+      +----------+
        //
        // The `opr` represents the node which was inserted by the `Branch 6` operation.
        // The origin node has been removed.
        assert_eq!(children.len(), 3);
        assert_eq!(children.item(1).unwrap(), child_opr_clone.as_child_node());
        assert_eq!(child_opr_clone.parent(), Some(document.as_parent_node()));
        assert_eq!(
            document.document_element(),
            Some(child_opr_clone.into_element().unwrap())
        );

        // Branch 10: We insert a new `Element` node into the list.
        let child_new = document.create_element("Element").unwrap();
        let ref_child = children.item(0).unwrap();
        // We cannot insert another `Element` into the list, because there already has
        // one.
        assert_eq!(
            document.insert_before(child_new, &ref_child).err(),
            Some(DomException::HierarchyRequestErr.into()),
        );
    }

    /// UT test case for `Document::replace_child()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Add any number of child nodes to the `document`.
    /// 3. Call `replace_child()` method to replace some of the nodes of `document`.
    /// 4. Check if the children list of `document` is correct.
    #[test]
    fn ut_document_replace_child() {
        // Create a document to be tested.
        let mut document = Document::new();
        // Add a child to it, because we need a `old_child` to be replaced.
        let child_init_first = document.create_comment("Comment").unwrap();
        let _ = document.append_child(child_init_first);
        assert!(document.has_children());

        // Get a reference to the document's children.
        let children = document.children();

        // Branch 1: The given `new_child` is not from the same document.
        let other_document = Document::new();
        let other_child = other_document.create_comment("Comment").unwrap();
        let old_child = children.item(0).unwrap();
        assert_eq!(
            document.replace_child(other_child, &old_child).err(),
            Some(DomException::WrongDocumentErr.into()),
        );

        // Branch 2: The given `new_child` is not an allowed child node.
        let child_not_allowed = document.create_text("Comment").unwrap();
        let old_child = children.item(0).unwrap();
        assert_eq!(
            document.replace_child(child_not_allowed, &old_child).err(),
            Some(DomException::HierarchyRequestErr.into()),
        );

        // Branch 3: Cannot find the given `old_child`.
        let child_allowed = document.create_comment("Comment").unwrap();
        let child_not_belongs_to_it = document.create_comment("Comment").unwrap();
        assert_eq!(
            document
                .replace_child(child_allowed, &child_not_belongs_to_it)
                .err(),
            Some(DomException::NotFoundErr.into()),
        );

        // Before the following tests, we remove the `opr` node in the children list.
        let child_init_second = document.create_comment("Comment").unwrap();
        let _ = document.append_child(child_init_second);
        let child_init_third = document.create_comment("Comment").unwrap();
        let _ = document.append_child(child_init_third);
        // After this operation, the list is as follows:
        //
        // list:                                   document_element:
        // +----------+----------+----------+      +----------+
        // |   first  |  second  |  third   |      |  (None)  |
        // +----------+----------+----------+      +----------+
        //
        // `first` represents the first node inserted.
        // `second` represents the second node inserted.
        // `third` represents the third node inserted.
        // `document_element` is empty because there are no `Element` nodes in the list.
        assert_eq!(children.len(), 3);

        // Branch 4: Insert a non-`Element` node that is not currently in the list.
        let child_opr = document.create_comment("Comment").unwrap();
        let child_opr_clone = child_opr.clone();
        let old_child = children.item(1).unwrap();
        assert!(document.replace_child(child_opr, &old_child).is_ok());
        // After this operation, the list is as follows:
        //
        // list:                                   document_element:
        // +----------+----------+----------+      +----------+
        // |   first  |    opr   |  third   |      |  (None)  |
        // +----------+----------+----------+      +----------+
        //
        // `second` node is replaced by `opr` node.
        assert_eq!(children.len(), 3);
        assert_eq!(children.item(1).unwrap(), child_opr_clone.as_child_node());
        assert_eq!(document.document_element(), None);
        assert_eq!(child_opr_clone.parent(), Some(document.as_parent_node()));

        // Branch 5: Inserts a non-`Element` node that exists in the current list.
        // The insertion position is before it.
        let child_opr = children.item(1).unwrap();
        let child_opr_clone = child_opr.clone();
        let old_child = children.item(0).unwrap();
        assert!(document.replace_child(child_opr, &old_child).is_ok());
        // After this operation, the list is as follows:
        //
        // list:                        document_element:
        // +----------+----------+      +----------+
        // |    opr   |  third   |      |  (None)  |
        // +----------+----------+      +----------+
        //
        // `first` node is removed.
        assert_eq!(children.len(), 2);
        assert_eq!(children.item(0).unwrap(), child_opr_clone);
        assert_eq!(document.document_element(), None);
        assert_eq!(child_opr_clone.parent(), Some(document.as_parent_node()));

        // Branch 6: Inserts a non-Element` node that exists in the current list.
        // The insertion position is after it.
        let child_opr = children.item(0).unwrap();
        let child_opr_clone = child_opr.clone();
        let old_child = children.item(1).unwrap();
        assert!(document.replace_child(child_opr, &old_child).is_ok());
        // After this operation, the list is as follows:
        //
        // list:            document_element:
        // +----------+     +----------+
        // |   opr    |     |  (None)  |
        // +----------+     +----------+
        //
        // `third` node is removed.
        assert_eq!(children.len(), 1);
        assert_eq!(children.item(0).unwrap(), child_opr_clone);
        assert_eq!(document.document_element(), None);
        assert_eq!(child_opr_clone.parent(), Some(document.as_parent_node()));

        // Restore to the original state.
        let child_init_first = document.create_comment("Comment").unwrap();
        let _ = document.replace_child(child_init_first, &child_opr_clone);
        let child_init_second = document.create_comment("Comment").unwrap();
        let _ = document.append_child(child_init_second);
        let child_init_third = document.create_comment("Comment").unwrap();
        let _ = document.append_child(child_init_third);
        assert_eq!(children.len(), 3);
        // After this operation, the list is as follows:
        //
        // list:                                   document_element:
        // +----------+----------+----------+      +----------+
        // |   first  |  second  |  third   |      |  (None)  |
        // +----------+----------+----------+      +----------+

        // Branch 7: 插入一个 `Element` 节点，且当前列表中不含有该节点。
        let child_opr = document.create_element("Element").unwrap();
        let child_opr_clone = child_opr.clone();
        let old_child = children.item(1).unwrap();
        assert!(document.replace_child(child_opr, &old_child).is_ok());
        // After this operation, the list is as follows:
        //
        // list:                                   document_element:
        // +----------+----------+----------+      +----------+
        // |   first  |    opr   |  third   |      |    opr   |
        // +----------+----------+----------+      +----------+
        //
        // `second` node is replaced by `opr` node.
        assert_eq!(children.len(), 3);
        assert_eq!(children.item(1).unwrap(), child_opr_clone.as_child_node());
        assert_eq!(child_opr_clone.parent(), Some(document.as_parent_node()));
        assert_eq!(document.document_element(), Some(child_opr_clone));

        // Branch 8:
        // Inserts an `Element` node with other `Element` nodes in the current list.
        // The insertion position is other than the `Element` node in this list.
        let child_new = document.create_element("Element").unwrap();
        let old_child = children.item(2).unwrap();
        assert_eq!(
            document.replace_child(child_new, &old_child).err(),
            Some(DomException::HierarchyRequestErr.into()),
        );
        // After this operation, the list is as follows:
        //
        // list:                                   document_element:
        // +----------+----------+----------+      +----------+
        // |   first  |    opr   |  third   |      |    opr   |
        // +----------+----------+----------+      +----------+

        // Branch 9: Inserts an `Element` node with other `Element` nodes in the current list.
        // The insertion position is the position of the `Element` node in this list.
        let child_new = document.create_element("Element").unwrap();
        let child_new_clone = child_new.clone();
        let old_child = children.item(1).unwrap();
        assert!(document.replace_child(child_new, &old_child).is_ok());
        // After this operation, the list is as follows:
        //
        // list:                                   document_element:
        // +----------+----------+----------+      +----------+
        // |   first  |    new   |  third   |      |    new   |
        // +----------+----------+----------+      +----------+
        //
        // `opr` node is replaced by `new`。
        assert_eq!(children.len(), 3);
        assert_eq!(children.item(1).unwrap(), child_new_clone.as_child_node());
        assert_eq!(child_new_clone.parent(), Some(document.as_parent_node()));
        assert_eq!(document.document_element(), Some(child_new_clone));

        // Branch 10: Inserts a non-`Element` node with an `Element` node in the current list.
        // The insertion position is the position of the `Element` node in this list.
        let child_new = document.create_comment("Comment").unwrap();
        let child_new_clone = child_new.clone();
        let old_child = children.item(1).unwrap();
        assert!(document.replace_child(child_new, &old_child).is_ok());
        // After this operation, the list is as follows:
        //
        // list:                                   document_element:
        // +----------+----------+----------+      +----------+
        // |   first  |    new   |  third   |      |  (None)  |
        // +----------+----------+----------+      +----------+
        assert_eq!(children.len(), 3);
        assert_eq!(children.item(1).unwrap(), child_new_clone.as_child_node());
        assert_eq!(child_new_clone.parent(), Some(document.as_parent_node()));
        assert_eq!(document.document_element(), None);
    }

    /// UT test case for `Document::remove_child()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Add any number of child nodes to the `document`.
    /// 3. Call `remove_child()` method to remove some of the nodes of `document`.
    /// 4. Check if the children list of `document` is correct.
    #[test]
    fn ut_document_remove_child() {
        // Create a `Document`.
        let mut document = Document::new();
        // Pre-insert two nodes, one `Element` node and one non `Element` node.
        let comment_child = document.create_comment("Comment").unwrap();
        let comment_child_clone = comment_child.clone();
        let element_child = document.create_element("Element").unwrap();
        let element_child_clone = element_child.clone();
        let _ = document.append_child(comment_child);
        let _ = document.append_child(element_child);
        // Get `Document`'s children list.
        let children = document.children();
        assert_eq!(children.len(), 2);
        assert_eq!(
            document.document_element(),
            Some(element_child_clone.clone())
        );

        // Branch 1: Delete nodes that are not part of this list.
        let other_child = document.create_comment("Comment").unwrap();
        assert_eq!(
            document.remove_child(&other_child).err(),
            Some(DomException::NotFoundErr.into()),
        );

        // Branch 2: Remove non `Element` nodes.
        assert!(document.remove_child(&comment_child_clone).is_ok());
        assert_eq!(children.len(), 1);
        assert_eq!(
            document.document_element(),
            Some(element_child_clone.clone())
        );

        // Branch 2: Remove the `Element` node.
        assert!(document.remove_child(&element_child_clone).is_ok());
        assert_eq!(children.len(), 0);
        assert_eq!(document.document_element(), None);
    }

    /// UT test case for `Document::append_child()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Add any number of child nodes to the `document`.
    /// 3. Call `append_child()` method to append some additional nodes to `document`.
    /// 4. Check if the children list of `document` is correct.
    #[test]
    fn ut_document_append_child() {
        // Create a `Document`.
        let mut document = Document::new();
        // Get `Document`'s children list.
        let children = document.children();

        // Branch 1: Inserts a non `Element` node that does not have the same node in the list.
        let comment_child = document.create_comment("Comment").unwrap();
        let comment_child_clone = comment_child.clone();
        assert!(document.append_child(comment_child).is_ok());
        assert_eq!(children.len(), 1);
        assert_eq!(
            children.item(0).unwrap(),
            comment_child_clone.as_child_node()
        );
        assert_eq!(document.document_element(), None);

        // Branch 2: Insert an `Element` node with the same node in the list.
        let comment_child = comment_child_clone;
        let comment_child_clone = comment_child.clone();
        assert!(document.append_child(comment_child).is_ok());
        assert_eq!(children.len(), 1);
        assert_eq!(
            children.item(0).unwrap(),
            comment_child_clone.as_child_node()
        );
        assert_eq!(document.document_element(), None);

        // Branch 3: Inserts an `Element` node that does not have the same node in the list.
        let element_child = document.create_element("Element").unwrap();
        let element_child_clone = element_child.clone();
        assert!(document.append_child(element_child).is_ok());
        assert_eq!(children.len(), 2);
        assert_eq!(
            children.item(1).unwrap(),
            element_child_clone.as_child_node()
        );
        assert_eq!(
            document.document_element(),
            Some(element_child_clone.clone())
        );

        // Branch 4: Insert an `Element` node with the same node in the list.
        let element_child = element_child_clone;
        let element_child_clone = element_child.clone();
        assert!(document.append_child(element_child).is_ok());
        assert_eq!(children.len(), 2);
        assert_eq!(
            children.item(1).unwrap(),
            element_child_clone.as_child_node()
        );
        assert_eq!(document.document_element(), Some(element_child_clone));

        // Branch 5: Insert an `Element` node with other `Element`s in the list.
        let element_child = document.create_element("Element").unwrap();
        assert_eq!(
            document.append_child(element_child).err(),
            Some(DomException::HierarchyRequestErr.into()),
        );
    }

    /// UT test case for `Document::document_element()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Add any number of child nodes to the `document`.
    /// 3. Call `document_element()` method to obtain the document element.
    /// 4. Check if the document element of `document` is correct.
    #[test]
    fn ut_document_document_element() {
        let mut document = Document::new();
        assert_eq!(document.document_element(), None);

        let element = document.create_element("Element").unwrap();
        let element_clone = element.clone();
        let _ = document.append_child(element);
        assert_eq!(document.document_element(), Some(element_clone));
    }

    /// UT test case for `Document::xml_encoding()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Call `xml_encoding()` method to obtain the document's encoding.
    /// 3. Check if the encoding is correct.
    #[test]
    fn ut_document_xml_encoding() {
        let document = Document::new();
        assert_eq!(document.xml_encoding(), None);
    }

    /// UT test case for `Document::set_xml_encoding()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Call `set_xml_encoding()` method to set a new encoding to the document.
    /// 3. Check if the encoding is correct.
    #[test]
    fn ut_document_set_xml_encoding() {
        let mut document = Document::new();
        assert_eq!(document.xml_encoding(), None);

        document.set_xml_encoding(Some(Encoding::Utf8));
        assert_eq!(document.xml_encoding(), Some(Encoding::Utf8));
    }

    /// UT test case for `Document::version()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Call `version()` method to obtain the document's version.
    /// 3. Check if the version is correct.
    #[test]
    fn ut_document_version() {
        let document = Document::new();
        assert_eq!(document.version(), "1.0");
    }

    /// UT test case for `Document::set_version()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Call `set_version()` method to set a new version to the document.
    /// 3. Check if the version is correct.
    #[test]
    fn ut_document_set_version() {
        let mut document = Document::new();
        assert_eq!(document.version(), "1.0");

        assert!(document.set_version("abcdefg").is_err());

        assert!(document.set_version("1.1").is_ok());
        assert_eq!(document.version(), "1.1");
    }

    /// UT test case for `Document::standalone()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Call `standalone()` method to obtain the standalone of the document.
    /// 3. Check if the standalone is correct.
    #[test]
    fn ut_document_standalone() {
        let document = Document::new();
        assert_eq!(document.standalone(), None);
    }

    /// UT test case for `Document::standalone()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Call `set_standalone()` method to set a new standalone to the document.
    /// 3. Check if the standalone is correct.
    #[test]
    fn ut_document_set_standalone() {
        let mut document = Document::new();
        assert_eq!(document.standalone(), None);

        document.set_standalone(Some(true));
        assert_eq!(document.standalone(), Some(true));
    }

    /// UT test case for `Document::create_element()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Call `create_element()` method to create a new `Element`.
    /// 3. Check if the `Element` is correct.
    #[test]
    fn ut_create_element() {
        let document = Document::new();
        let element = document.create_element("Element").unwrap();
        assert_eq!(element.name(), "Element");
        assert_eq!(element.attributes().len(), 0);
        assert_eq!(element.children().len(), 0);
        assert_eq!(element.parent(), None);
        assert_eq!(element.owner_document(), Some(document));
    }

    /// UT test case for `Document::create_text()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Call `create_text()` method to create a new `Text`.
    /// 3. Check if the `Text` is correct.
    #[test]
    fn ut_create_text() {
        let document = Document::new();
        let text = document.create_text("Text").unwrap();
        assert_eq!(text.value(), "Text");
        assert_eq!(text.parent(), None);
        assert_eq!(text.owner_document(), Some(document));
    }

    /// UT test case for `Document::create_comment()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Call `create_comment()` method to create a new `Comment`.
    /// 3. Check if the `Comment` is correct.
    #[test]
    fn ut_create_comment() {
        let document = Document::new();
        let comment = document.create_comment("Comment").unwrap();
        assert_eq!(comment.value(), "Comment");
        assert_eq!(comment.parent(), None);
        assert_eq!(comment.owner_document(), Some(document));
    }

    /// UT test case for `Document::create_cdata_section()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Call `create_cdata_section()` method to create a new `CdataSection`.
    /// 3. Check if the `CdataSection` is correct.
    #[test]
    fn ut_create_cdata_section() {
        let document = Document::new();
        let cdata_section = document.create_comment("CDATASection").unwrap();
        assert_eq!(cdata_section.value(), "CDATASection");
        assert_eq!(cdata_section.parent(), None);
        assert_eq!(cdata_section.owner_document(), Some(document));
    }

    /// UT test case for `Document::create_attribute()`.
    ///
    /// # Brief
    /// 1. Create a `Document` called `document`.
    /// 2. Call `create_attribute()` method to create a new `Attribute`.
    /// 3. Check if the `Attribute` is correct.
    #[test]
    fn ut_create_attribute() {
        let document = Document::new();
        let attribute = document.create_attribute("Attribute", "Value").unwrap();
        assert_eq!(attribute.name(), "Attribute");
        assert_eq!(attribute.value(), "Value");
        assert_eq!(attribute.owner_document(), Some(document));
    }
}
